﻿"use strict";

const roomMgr = require("../roomMgr");
const clientMgr = require("../clientMgr");
const socket = require('../../base_net/socket');
const crypto = require('../../utils/crypto');
const db = require("../../utils/db");
const logger = require("../../utils/logger");
var utils = require("../../utils/utils");
const { game } = require("../../utils/logger");

var games = {};
var gameSeatsOfUsers = {};
//超过半小时自动解散
var  kickList = {};

var DZOptionalOperate = {
    CALL: 1,
    CALL_RAISE: 2,
    RAISE: 3,
}

var CARD_TYPE = {
    ROYAL_SAME_DECOR_STRAIGHT: 19,
    SAME_DECOR_STRAIGHT: 18,
    BOMB: 17,
    GOURD: 16,
    SAME_DECOR: 15,
    STRAIGHT: 14,
    LEOPARD: 13,
    TWO_PAIR: 12,
    ONE_PAIR: 11,
}

var CardDecor = {
    HEART: 2,   // 红桃
    BLOCK: 4,   // 方块
    SPADE: 1,   // 黑桃
    PLUM: 3,    // 梅花
}

exports.setReady = function(userId,value){
    var roomId = roomMgr.getUserRoomId(userId);
    if(roomId == null){
        return;
    }
    var roomInfo = roomMgr.getRoom(roomId);
    if(roomInfo == null){
        return;
    }
    var seatIndex = roomMgr.getUserIndex(userId);
    if(seatIndex == null){
        return;
    }
    var s = roomInfo.seats[seatIndex];
    s.ready = value?true:false;
    clientMgr.broadcastInRoom(socket.resp.user_ready,{userId:userId,ready:value},userId,true);
    if((kickList[userId] || kickList[userId] >= 0) && s.sit == 1){
        delete kickList[userId];
    }

    var game = games[ roomId ];
    if( game == null ) {
        var count = 0;
        for( var i = 0; i < roomInfo.seats.length; ++i ) {
            var s = roomInfo.seats[ i ];
            if( s && s.userId > 0 && s.sit == 1){
                if(s.ready == false){
                    if(roomInfo.conf.maxGames > 0)return;
                    continue;
                }
                count ++;
            }
        }
        if(count <= 1)return;
        if(roomInfo.numOfGames == 0){
            roomMgr.setStart( roomId );
        }
        logger.game_log("启动德州扑克游戏");
        //人数已经到齐了，并且都准备好了，则开始新的一局
        begin( roomId );
    }
}

exports.gameBegin = function(roomInfo){
    var roomId = roomInfo.roomId;
    if(roomInfo.numOfGames == 0){
        roomMgr.setStart( roomId );
    }
    logger.game_log("启动德州扑克游戏");
    //人数已经到齐了，并且都准备好了，则开始新的一局
    var game = games[ roomId ];
    if( game == null ) {
        begin(roomId);
    }
}
exports.sitDown = function(userId,value){
    var roomId = roomMgr.getUserRoomId(userId);
    if(roomId == null){
        return;
    }
    var roomInfo = roomMgr.getRoom(roomId);
    if(roomInfo == null){
        return;
    }
    var seatIndex = roomMgr.getUserIndex(userId);
    if(seatIndex == null){
        return;
    }

    var s = roomInfo.seats[seatIndex];
    s.sit = value == false?0:1;
    getNiuniu2(userId);
    clientMgr.broadcastInRoom(socket.resp.user_sit,{userId:userId,sit:s.sit},userId,true);

    if(roomInfo.numOfGames > 0 || roomInfo.conf.maxGames <= 0){
        delete kickList[userId];
    }
}
exports.syncInfo = function(userId){
    var roomId = roomMgr.getUserRoomId(userId);
    if(roomId == null){
        return;
    }
    var roomInfo = roomMgr.getRoom(roomId);
    if(roomInfo == null || roomInfo.numOfGames == 0){
        return;
    }

    var game = games[ roomId ];
    var data = {};
    if( game != null ) {
        var ddd = game.gameSeats[game.button];

        data = {
            state : game.state,
            fundPool: game.fundPool,
            gameState:roomInfo.gameState,
            button : ddd != null?ddd.userId:0,
        };
        data.commonHolds = game.commonHolds;
        data.callNowCost = game.callNowCost;
        data.raiseNowCost = getRaiseBetCost(game);
        if (game.turnGamber != null) {
            data.gamber = game.gameSeats[game.turnGamber].userId;
            data.operates = getOptionalOperate(game, game.turnGamber);
        }
        data.seats = [];
        for(var i = 0; i < roomInfo.conf.roomNum; ++i) {
            var rs = roomInfo.seats[i];
            var sd = game.gameSeats[i];
            if( !sd ) continue;
            
            if(sd.userId == userId){
                rs.exitAfterEnd = false;
            }

            var s = {
                userId:sd.userId,
                scoreBetting : sd.scoreLast,
                hasEliminate : sd.eliminate,
                // score2 : sd.score2,
                // hasLiang : sd.hasLiang,
                sit : sd.sit,
                ready : rs.ready,
            }

            var holds = null;
            if(data.state == 5){
                holds = sd.holds;
                var niu = calculate(holds);
                s.niu = niu;
            }
            else{
                if(sd.sit == 1 && sd.userId == userId){
                    holds = utils.clone(sd.holds);
                    holds[holds.length-1] = -1;
                }
            }
            s.holds = holds;
            data.seats.push(s);
        }
    }
    else{
        data = {
            state : 0,
            gameState:roomInfo.gameState,
        };
        data.seats = [];
        for(var i = 0; i < roomInfo.conf.roomNum; ++i) {
            var sd = roomInfo.seats[i];
            if( sd.userId <= 0 ) continue;

            var s = {
                userId:sd.userId,
                ready : sd.ready,
                sit : sd.sit,
            }
            data.seats.push(s);
        }
    }
    data.record = roomInfo.allRecord;
    //同步整个信息给客户端
    clientMgr.sendMsg(userId,socket.resp.game_sync,data);
}

exports.get_tick_time = function(userId) {
    var roomId = roomMgr.getUserRoomId(userId);
    if(roomId == null){
        return;
    }
    var roomInfo = roomMgr.getRoom(roomId);
    if(roomInfo == null){
        return null;
    }
    if(kickList[userId] == null || kickList[userId] <= 0) {
        var seatIndex = roomMgr.getUserIndex(userId);
        if (seatIndex == null || seatIndex == 0) {
            return kickList;
        }
        var s = roomInfo.seats[seatIndex];
        if (s.sit == 0 || (s.ready == 0 && roomInfo.conf.maxGames > 0)) {
            kickList[userId] = 120;
        }
        /*else if (s.ready == 0) {
            kickList[userId] = 120;
        }*/
    }
    return kickList;
}
exports.setNiuniu = function(userId) {
    db.niuniu_permission(userId,function (code) {
        if(code == 2)return;
        if(code == 1){
            clientMgr.sendMsg(userId, socket.resp.niuniu_resp,{code:1});
            return;
        }
        var roomId = roomMgr.getUserRoomId(userId);
        if(roomId == null){
            return;
        }
        var roomInfo = roomMgr.getRoom(roomId);
        if(roomInfo == null){
            return;
        }
        var seatIndex = roomMgr.getUserIndex(userId);
        if(seatIndex == null){
            return;
        }
        var s = roomInfo.seats[seatIndex];
        s.setNiuniu = true;
        clientMgr.sendMsg(userId, socket.resp.niuniu_resp,{code:0});
    })
}

function getNiuniu2(userId) {
    db.getNiuniu2(userId,function (rate) {
        var roomId = roomMgr.getUserRoomId(userId);
        if(roomId == null){
            return;
        }
        var roomInfo = roomMgr.getRoom(roomId);
        if(roomInfo == null){
            return;
        }
        var seatIndex = roomMgr.getUserIndex(userId);
        if(seatIndex == null){
            return;
        }
        var s = roomInfo.seats[seatIndex];
        s.setNiuniu2 = rate;
    })
}
exports.exitAfterEnd = function (roomInfo,seatIndex){
    // if(roomInfo.owner == "999999"){
        var game = games[ roomInfo.roomId ];
        if( game == null ) {
            return false;
        }
        else{
            roomInfo.seats[seatIndex].exitAfterEnd = true;
            return true;
        }
    // }
    return true;
}
function clearExit(roomInfo) {
    if (roomInfo == null) return;
    var roomId = roomInfo.roomId;
    for(var i = 0; i < roomInfo.seats.length; ++i) {
        var rs = roomInfo.seats[i];
        if(rs.exitAfterEnd) {// || clientMgr.isOnline(rs.userId) == false){
            if (rs.exitAfterEnd && roomMgr.isCreator(roomId, rs.userId)) {
                clientMgr.broadcastInRoom(socket.resp.dispress,"dispress",rs.userId,false);
                clientMgr.kickAllInRoom(roomId);
                roomMgr.destroy(roomId);
                return;
            }
            rs.exitAfterEnd = false;
            clientMgr.sendMsg(rs.userId,socket.resp.exit_result,rs.userId);
            //通知其它玩家，有人退出了房间
            clientMgr.broadcastInRoom(socket.resp.exit_notify,rs.userId,rs.userId,false);

            roomMgr.exitRoom(rs.userId);
        }
    }
}
//开始新的一局
function begin(roomId) {
    var state = {
        idle : 0,
        // qiangzhuang : 1,
        dingzhuang : 2,
        xiazhu : 3,
        // cuopai : 4,
        bipai : 5,
    };

    var roomInfo = roomMgr.getRoom(roomId);
    if(roomInfo == null || games[roomId] != null){
        return;
    }

    clearExit(roomInfo);

    var roomInfo = roomMgr.getRoom(roomId);
    if(roomInfo == null || games[roomId] != null){
        return;
    }

    roomMgr.payGameCost(roomId);

    var seats = roomInfo.seats;

    var game = {
        conf:roomInfo.conf,
        roomInfo:roomInfo,
        allState : state,

        qiangzhuangTime : 3,
        dingzhuangTime : 3,
        xiazhuTime : 15,
        cuopaiTime : 10,
        liangpaiTime  : 4,
        nextGameTime : 20,

        allCards : [],
        currentIndex:0,
        gameSeats:[],

        isNiuniu : false,
        button: 0,
        state:0,
        raiseTime: 0,
        commonHolds: [],
        fundPool: 0,

        actionList:[],
    };
    roomInfo.numOfGames++;
    db.update_numOfGames(roomId,roomInfo.numOfGames);

    for(var i = 0; i < game.conf.roomNum; ++i) {
        if(seats[i].userId <= 0)continue;
        var data = game.gameSeats[i] = {};
        data.game = game;		//循环引用
        data.seatIndex = i;

        data.sit = seats[i].sit;
        data.userId = seats[i].userId;
        //持有的牌
        data.holds = [];

        data.score = 0;
        //抢庄倍数
        data.hasQiang = false;
        data.score1 = 0;
        //下注倍数
        data.hasXia = false;
        data.scoreBetting = 0;
        data.hasLiang = false;
        data.tryCards = null;

        data.eliminate = false;

        // data.setNiuniu = seats[i].setNiuniu;
        // data.setNiuniu2 = seats[i].setNiuniu2;
        gameSeatsOfUsers[data.userId] = data;
    }

    var allHolds = [];
    var count = 0;
    for(var i = 0; i < seats.length; ++i) {
        if (!game.gameSeats[i]) continue;
        //开局时，通知前端必要的数据
        var s = seats[i];
        if(s.ready == 1){
            count += 1;
        }
    }
    if(count <= 1){
        if(roomInfo.owner != "999999"){
            // doGameOver2(game,roomId,true);
        }
        return;
    }
    roomInfo.gameState = "playing";
    clientMgr.broadcastInRoom2(socket.resp.game_state,{state:roomInfo.gameState},roomId);

    games[roomId] = game;
    //洗牌
    shuffle(game);
    //发牌
    deal(game);
    // createNiuniu2(game);
    // createNiuniu(game);

    for(var i = 0; i < seats.length; ++i) {
        if (!game.gameSeats[i]) continue;
        //开局时，通知前端必要的数据
        var s = seats[i];
        //通知游戏开始
        clientMgr.sendMsg(s.userId, socket.resp.game_begin);
        //通知玩家手牌
        //var holds = utils.clone(game.gameSeats[i].holds);
        //holds[holds.length-1] = -1;
        //var data = {userId:s.userId,holds:holds};
        //clientMgr.sendMsg(s.userId, socket.resp.game_holds, [data]);
        allHolds.push({userId:s.userId,holds:game.gameSeats[i].holds,sit:s.sit});
        //通知还剩多少局
        clientMgr.sendMsg(s.userId, socket.resp.game_num, roomInfo.numOfGames);
        // 更新权限
        updatePermission(s.userId);
    }
    for(var i = 0; i < seats.length; ++i) {
        if (!game.gameSeats[i]) continue;
        var s = seats[i];
        var allHolds2 = utils.clone(allHolds);
        for(var j=0;j<allHolds2.length;j++){
            var holds = allHolds2[j].holds;
            // if(s.sit == 1 && s.userId == allHolds2[j].userId){
            //     allHolds2[j].holds = [-1, -1, -1];
            // }
            if(s.sit == 1) {
                allHolds2[j].holds = null;
            }
        }
        logger.game_log("当前手牌为", allHolds2);
        // clientMgr.sendMsg(s.userId, socket.resp.game_holds, allHolds2);
    }
    recordGameAction(game,socket.resp.game_begin);
    recordGameAction(game,socket.resp.game_holds,allHolds);
    recordGameAction(game,socket.resp.game_num,roomInfo.numOfGames);

    // game.state = game.allState.qiangzhuang;
    // clientMgr.broadcastInRoom2(socket.resp.qiangzhuang_all,{time:game.qiangzhuangTime},game.roomInfo.roomId,true);
    // recordGameAction(game,socket.resp.qiangzhuang_all,{time:game.qiangzhuangTime});
    setBanker(game);
    // game.timeId1 = setTimeout(function () {
    //     dingzhuang(game);
    // },game.qiangzhuangTime * 1000);
};

function setBanker(game){
    var indexArr = [];
    var userArr = [];
    for (var i=0;i<game.gameSeats.length;i++){
        var seatData = game.gameSeats[i];
        if(!seatData || seatData.sit == 0)continue;
        if(seatData.userId > 0){
            indexArr.push(i);
            userArr.push(seatData.userId);
        }
    }
    // 第一轮的庄家是随机的，后面的庄家都是上一轮的胜利者
    if (game.roomInfo.smallBlindBetIndex) {
        game.button = getNextUserIndex(game, game.button);
    } else {
        var random = Math.floor(Math.random()*indexArr.length);
        game.button = indexArr[random];
    }

    game.smallBlindBetIndex = getNextUserIndex(game, game.button);
    game.bigBlindBetIndex = getNextUserIndex(game, game.smallBlindBetIndex);
    game.bigBlindBet = game.conf.difen;
    game.smallBlindBet = Math.ceil(game.bigBlindBet / 2);

    game.round = 0;
    
    var banker = game.gameSeats[game.button];   // 庄家
    game.state = game.allState.dingzhuang;
    
    clientMgr.broadcastInRoom2(socket.resp.dingzhuang_all,{time:game.dingzhuangTime,button:banker.userId,userArr:userArr},game.roomInfo.roomId,true);
    recordGameAction(game,socket.resp.dingzhuang_all,{time:game.dingzhuangTime,button:banker.userId,userArr:userArr});

    // 上一个加注的人
    game.lastRaiseIndex = null;
    // 加注次数
    game.raiseTime = 0;

    
    game.timeId2 = setTimeout(function () {
        game.turnGamber = game.smallBlindBetIndex;
        // 最低加注
        game.minRaiseScore = game.bigBlindBet;
        game.lastRaiseScore = game.bigBlindBet;
        xiazhu(game, game.smallBlindBetIndex, game.smallBlindBet, true);
        xiazhu(game, game.bigBlindBetIndex, game.bigBlindBet, true);
        // game.lastRaiseIndex = game.turnGamber;
        // game.round = 1;
        betting(game);
    },game.dingzhuangTime * 1000);
}

function isGameOver(game) {
    if (game.round >= 4) {
        return true;
    }
    var gamberNum = 0;
    for (var i = 0; i < game.gameSeats.length; ++i){
        var user = game.gameSeats[i];
        if (!user || user.sit == 0)continue;
        if (user.eliminate) continue;
        if (user.userId > 0){
            gamberNum += 1;
            if (gamberNum > 1) {
                return false;
            }
        }
    }
    return true;
}

function dealRound(game) {
    if (game.round == 1) {
        // 给玩家发两张手牌
        var allHolds = [];
        var seats = game.gameSeats;
        for(var i = 0; i < seats.length; ++i) {
            if (!game.gameSeats[i]) continue;
            //开局时，通知前端必要的数据
            var s = seats[i];
            allHolds.push({userId:s.userId,holds:game.gameSeats[i].holds,sit:s.sit});
        }
        for(var i = 0; i < seats.length; ++i) {
            if (!game.gameSeats[i]) continue;
            var s = seats[i];
            var allHolds2 = utils.clone(allHolds);
            for(var j=0;j<allHolds2.length;j++){
                var holds = allHolds2[j].holds;
                if(s.sit == 1 && s.userId == allHolds2[j].userId){
                    
                } else if(s.sit == 1) {
                    allHolds2[j].holds = null;
                }
            }
            clientMgr.sendMsg(s.userId, socket.resp.game_holds, allHolds2);
        }
        // clientMgr.sendMsg(s.userId, socket.resp.game_holds, allHolds2);
    } else if (game.round == 2) {
        // 发3张公共牌
        for (var i = 0; i < 3; ++i) {
            var pai = game.allCards[game.currentIndex];
            game.currentIndex ++;
            game.commonHolds.push( pai );
        }
        clientMgr.broadcastInRoom2(socket.resp.game_common_holds,{commonHolds:game.commonHolds},game.roomInfo.roomId,true);
    } else if (game.round == 3 || game.round == 4) {
        // 发1张公共牌
        var pai = game.allCards[game.currentIndex];
        game.currentIndex ++;
        game.commonHolds.push( pai );
        clientMgr.broadcastInRoom2(socket.resp.game_common_holds,{commonHolds:game.commonHolds},game.roomInfo.roomId,true);
    }
}

function betting(game) {
    if (game.timerIdBetting != null) {
        clearTimeout(game.timerIdBetting);
    }
    if (game.lastRaiseIndex == null) {
        game.lastRaiseIndex = game.turnGamber;
    }
    if (game.lastRaiseIndex == game.turnGamber) {
        game.round += 1;
        game.raiseTime = 0;
        dealRound(game);
    }
    if (isGameOver(game)) {
        bipai(game);
        return;
    }

    var userSeatIndex = game.turnGamber;
    
    var gambler = game.gameSeats[userSeatIndex];
    if(!gambler || gambler.sit == 0) {
        logger.game_log("下注阶段有人跑路了");
        return;
    }

    var op = null;
    if (game.raiseTime >= 3) {
        op = DZOptionalOperate.CALL;
    } else {
        op = DZOptionalOperate.CALL_RAISE;
    }
    
    var data = {time:game.xiazhuTime,gambler:gambler.userId,operates:op,callCost:game.callNowCost,raiseCost:getRaiseBetCost(game)};
    clientMgr.broadcastInRoom2(socket.resp.turn_betting_notify,data,game.roomInfo.roomId,true);
    // recordGameAction(game,socket.resp.zjh_turn_betting_notify,data);

    game.state = game.allState.xiazhu;

    game.timerIdBetting = setTimeout(function () {
        exports.bettingWaive(gambler.userId);
    }, game.xiazhuTime * 1000);
}

function getOptionalOperate(game) {
    if (game.raiseTime >= 3) {
        return DZOptionalOperate.CALL;
    } else {
        return DZOptionalOperate.CALL_RAISE;
    }
}

// function xiazhu(game){
//     var sd = game.gameSeats[game.button];
//     var score1 = sd.score1;
//     clientMgr.broadcastInRoom2(socket.resp.xiazhu_all,{time:game.xiazhuTime,button:sd.userId,beishu:score1},game.roomInfo.roomId,true);
//     recordGameAction(game,socket.resp.xiazhu_all,{time:game.xiazhuTime,button:sd.userId,beishu:score1});

//     game.state = game.allState.xiazhu;
//     game.timeId3 = setTimeout(function () {
//         cuopai(game);
//     },game.xiazhuTime * 1000);
// }
function cuopai(game){
    if(game.timeId3 <= 0)return;
    game.timeId3 = -1;
    for (var i=0;i<game.gameSeats.length;i++){
        var ddd = game.gameSeats[i];
        if(!ddd || ddd.sit == 0)continue;
        if(ddd.score2 == 0  && i != game.button){
            ddd.score2 = 2;
            clientMgr.broadcastInRoom(socket.resp.xiazhu_notify,{userId:ddd.userId,value:2},ddd.userId,true);
            recordGameAction(game,socket.resp.xiazhu_notify,{userId:ddd.userId,value:2});
        }
        var niu = calculate(ddd.holds);
        clientMgr.sendMsg(ddd.userId, socket.resp.cuopai_all, {time:game.cuopaiTime,holds:ddd.holds,niu:niu});
    }

    game.state = game.allState.cuopai;
    game.timeId4 = setTimeout(function () {
        var turnSeat = game.gameSeats[game.button];
        bipai(game,turnSeat.userId);
    },game.cuopaiTime * 1000);
}
function bipai(game){
    if(game.timeId4 <= 0)return;
    game.timeId4 = -1;

    for (var l=0;l<game.gameSeats.length;l++) {
        var ddd = game.gameSeats[l];
        if (!ddd) continue;
        if (!ddd.eliminate) {
            var niu = getCardType(game, ddd.holds);
        }
        if(ddd.hasLiang == false){
            clientMgr.broadcastInRoom(socket.resp.liangpai_notify, {userId: ddd.userId,holds: ddd.holds,niu:niu,sit:ddd.sit},ddd.userId,true);
            recordGameAction(game, socket.resp.liangpai_notify, {userId: ddd.userId,holds: ddd.holds,niu:niu,sit:ddd.sit});
        }
        clientMgr.sendMsg(ddd.userId, socket.resp.bipai_all, {time:game.liangpaiTime});
    }

    game.state = game.allState.bipai;
    game.timeId5 = setTimeout(function () {
        var banker = game.gameSeats[game.button];
        doGameOver(game,banker.userId);
    },game.liangpaiTime * 1000);
}

exports.qiangzhuang = function (userId,value) {
    var roomId = roomMgr.getUserRoomId(userId);
    if(roomId == null){
        return;
    }
    var seatIndex = roomMgr.getUserIndex(userId);
    if(seatIndex == null){
        return;
    }
    var game = games[ roomId ];
    if( game == null ) {
        return;
    }
    if(game.state != game.allState.qiangzhuang)return;

    var gs = game.gameSeats[seatIndex];
    gs.score1 = value;
    gs.hasQiang = true;
    clientMgr.broadcastInRoom(socket.resp.qiangzhuang_notify,{userId:userId,value:value},userId,true);
    recordGameAction(game,socket.resp.qiangzhuang_notify,{userId:userId,value:value});

    var hasOver = true;
    for (var i=0;i<game.gameSeats.length;i++) {
        var ddd = game.gameSeats[i];
        if(!ddd || ddd.sit == 0)continue;
        if(ddd.hasQiang == false){
            hasOver = false;
        }
    }
    if(hasOver){
        dingzhuang(game);
    }
}
function getNextUserIndex(game, userSeatIndex) {
    for (var i = 1; i < game.gameSeats.length; ++i){
        var index = (i + userSeatIndex) % game.gameSeats.length;
        var user = game.gameSeats[index];
        if (!user || user.sit == 0)continue;
        if (user.eliminate) continue;
        if (user.userId > 0){
            return index;
        }
    }
}
exports.bettingCall = function(userId) {
    var roomId = roomMgr.getUserRoomId(userId);
    if(roomId == null){
        return;
    }
    var roomInfo = roomMgr.getRoom(roomId);
    if(roomInfo == null){
        return;
    }
    var seatIndex = roomMgr.getUserIndex(userId);
    if(seatIndex == null){
        return;
    }
    var game = games[ roomId ];
    if( game == null ) {
        return;
    }
    if(game.state != game.allState.xiazhu)return;
    if (game.turnGamber != seatIndex) return;   // 不是轮到这个用户下注
    var user = roomInfo.seats[seatIndex];
    var gamber = game.gameSeats[seatIndex];
    var value = game.callNowCost;
    logger.game_log("已有金币", user.coins, "打算下注", value);
    // if (value > user.coins) {
    //     logger.game_log("金币不足");
    //     recordGameAction(game,socket.resp.betting_call_notify,{userId:userId,value:value,failed:1});
    //     return;
    // }
    xiazhu(game, seatIndex, value);
    // game.callNowCost = value;
    // gamber.scoreBetting += value;
    // clientMgr.broadcastInRoom(socket.resp.xiazhu_notify,{userId:userId,value:value},userId,true);
    // recordGameAction(game,socket.resp.betting_call_notify,{userId:userId,value:value});
    
    // game.turnGamber = getNextUserIndex(game, game.turnGamber);
    betting(game);
}
exports.bettingRaise = function(userId, value) {
    var roomId = roomMgr.getUserRoomId(userId);
    if(roomId == null){
        return;
    }
    var roomInfo = roomMgr.getRoom(roomId);
    if(roomInfo == null){
        return;
    }
    var seatIndex = roomMgr.getUserIndex(userId);
    if(seatIndex == null){
        return;
    }
    var game = games[ roomId ];
    if( game == null ) {
        return;
    }
    if(game.state != game.allState.xiazhu)return;
    if (game.turnGamber != seatIndex) return;   // 不是轮到这个用户下注
    if (game.raiseTime > 3) {
        logger.game_log("加注次数已满");
        return;
    }
    var user = roomInfo.seats[seatIndex];
    var gamber = game.gameSeats[seatIndex];
    logger.game_log("已有金币", user.coins, "打算下注", value);
    // if (value > user.coins) {
    //     logger.game_log("金币不足");
    //     recordGameAction(game,socket.resp.betting_raise_notify,{userId:userId,value:value,failed:1});
    //     return;
    // }
    // if (value > game.betTop || value < getRaiseBetCost(game)) {
    //     logger.game_log("下注金额不正确");
    //     recordGameAction(game,socket.resp.betting_raise_notify,{userId:userId,value:value,failed:2});
    //     return;
    // }
    xiazhu(game, seatIndex, value);
    // game.callNowCost = value;
    // gamber.scoreBetting += value;
    // clientMgr.broadcastInRoom(socket.resp.betting_raise_notify,{userId:userId,value:value},userId,true);
    // recordGameAction(game,socket.resp.betting_raise_notify,{userId:userId,value:value});
    
    // game.turnGamber = getNextUserIndex(game, game.turnGamber);
    betting(game);
}

function getRaiseBetCost(game) {
    if (game.round > 2) {
        return game.callNowCost + game.bigBlindBet * 2;
    } else {
        return game.callNowCost + game.bigBlindBet;
    }
}

function getCallBetCost(game) {
    return game.callNowCost;
}

function xiazhu(game, seatIndex, value, isBlind) {
    var gamber = game.gameSeats[seatIndex];
    var userId = gamber.userId;
    var isRaise = false;
    if (value >= getRaiseBetCost(game)) {
        game.lastRaiseIndex = game.turnGamber;
        game.raiseTime += 1;
        isRaise = true;
    }
    game.callNowCost = value;
    gamber.scoreBetting += value;
    gamber.scoreLast = value;

    changeScore(game, gamber, value);
    
    clientMgr.broadcastInRoom(socket.resp.xiazhu_notify,{userId:userId,value:value,isRaise:isRaise,isBlind:isBlind},userId,true);
    recordGameAction(game,socket.resp.xiazhu_notify,{userId:userId,value:value,isRaise:isRaise,isBlind:isBlind});
    
    game.turnGamber = getNextUserIndex(game, game.turnGamber);
}
exports.bettingWaive = function(userId) {
    var roomId = roomMgr.getUserRoomId(userId);
    if(roomId == null){
        return;
    }
    var roomInfo = roomMgr.getRoom(roomId);
    if(roomInfo == null){
        return;
    }
    var seatIndex = roomMgr.getUserIndex(userId);
    if(seatIndex == null){
        return;
    }
    var game = games[ roomId ];
    if( game == null ) {
        return;
    }
    if(game.state != game.allState.xiazhu)return;
    if (game.turnGamber != seatIndex) return;   // 不是轮到这个用户下注

    clientMgr.broadcastInRoom(socket.resp.betting_waive_notify,{userId:userId},userId,true);
    recordGameAction(game,socket.resp.betting_waive_notify,{userId:userId});
    
    var gamber = game.gameSeats[seatIndex];
    eliminateGamber(game, gamber);
    
    game.turnGamber = getNextUserIndex(game, game.turnGamber);
    betting(game);
}
// exports.bettingWatch = function(userId) {
//     var roomId = roomMgr.getUserRoomId(userId);
//     if(roomId == null){
//         return;
//     }
//     var roomInfo = roomMgr.getRoom(roomId);
//     if(roomInfo == null){
//         return;
//     }
//     var seatIndex = roomMgr.getUserIndex(userId);
//     if(seatIndex == null){
//         return;
//     }
//     var game = games[ roomId ];
//     if( game == null ) {
//         return;
//     }
//     if(game.state != game.allState.xiazhu)return;
//     if (game.turnGamber != seatIndex) return;   // 不是轮到这个用户下注
//     var gamber = game.gameSeats[seatIndex];

//     if (gamber.watchCardRound) {
//         logger.game_log(userId, "已经看过牌了");
//         return;
//     }
//     gamber.watchCardRound = game.round;
    
//     var op;
//     if (game.round == 1) {
//         op = ZJHOptionalOperate.CALL_RAISE;
//     } else {
//         op = ZJHOptionalOperate.CALL_RAISE_COMPARE;
//     }

//     clientMgr.sendMsg(userId, socket.resp.betting_watch_notify,{userId:userId,operates:op,holds:gamber.holds,callCost:game.callNowCost*2});
//     clientMgr.broadcastInRoom(socket.resp.betting_watch_notify,{userId:userId,operates:op,holds:[-1,-1,-1],callCost:game.callNowCost},userId,false);
//     recordGameAction(game,socket.resp.betting_watch_notify,{userId:userId,operates:op,holds:gamber.holds,callCost:game.callNowCost*2});
// }
function eliminateGamber(game, gamber) {
    gamber.eliminate = true;
    logger.game_log(gamber.userId, "被淘汰");
    clientMgr.broadcastInRoom(socket.resp.eliminate_notify,{userId:gamber.userId},gamber.userId,true);
    recordGameAction(game,socket.resp.eliminate_notify,{userId:gamber.userId});
}

// exports.bettingCompare = function(userId, cmpUserId) {
//     var roomId = roomMgr.getUserRoomId(userId);
//     if(roomId == null){
//         return;
//     }
//     var roomInfo = roomMgr.getRoom(roomId);
//     if(roomInfo == null){
//         return;
//     }
//     var seatIndex = roomMgr.getUserIndex(userId);
//     if(seatIndex == null){
//         return;
//     }
//     var game = games[ roomId ];
//     if( game == null ) {
//         return;
//     }
//     if(game.state != game.allState.xiazhu)return;
//     if (game.turnGamber != seatIndex) return;   // 不是轮到这个用户下注
//     var cmpSeatIndex = roomMgr.getUserIndex(cmpUserId);
//     if (cmpSeatIndex == null) {
//         return;
//     }
//     var gamber = game.gameSeats[seatIndex];
//     var cmpGamber = game.gameSeats[cmpSeatIndex];
//     var result = compare(gamber.holds, cmpGamber.holds) > 0 ? 1 : 0;

//     logger.game_log("比牌", userId, cmpUserId, result);
//     clientMgr.broadcastInRoom(socket.resp.betting_compare_notify,{userId:userId,cmpUserId:cmpUserId,result:result},userId,true);
//     recordGameAction(game,socket.resp.betting_compare_notify,{userId:userId,cmpUserId:cmpUserId,result:result});
    
//     if (result == 1) {
//         eliminateGamber(game, cmpGamber);
//     } else {
//         eliminateGamber(game, gamber);
//     }

//     game.turnGamber = getNextUserIndex(game, game.turnGamber);
//     betting(game);
// }
// exports.xiazhu = function (userId,value) {
//     var roomId = roomMgr.getUserRoomId(userId);
//     if(roomId == null){
//         return;
//     }
//     var seatIndex = roomMgr.getUserIndex(userId);
//     if(seatIndex == null){
//         return;
//     }
//     var game = games[ roomId ];
//     if( game == null ) {
//         return;
//     }
//     if(game.state != game.allState.xiazhu)return;

//     var gs = game.gameSeats[seatIndex];
//     gs.score2 = value;
//     gs.hasXia = true;
//     clientMgr.broadcastInRoom(socket.resp.xiazhu_notify,{userId:userId,value:value},userId,true);
//     recordGameAction(game,socket.resp.xiazhu_notify,{userId:userId,value:value});

//     var hasOver = true;
//     for (var i=0;i<game.gameSeats.length;i++) {
//         var ddd = game.gameSeats[i];
//         if(!ddd || i == game.button || ddd.sit == 0)continue;
//         if(ddd.hasXia == false){
//             hasOver = false;
//         }
//     }
//     if(hasOver){
//         cuopai(game);
//     }
// }
exports.kanpai = function (userId) {
    var roomId = roomMgr.getUserRoomId(userId);
    if(roomId == null){
        return;
    }
    var seatIndex = roomMgr.getUserIndex(userId);
    if(seatIndex == null){
        return;
    }
    var game = games[ roomId ];
    if( game == null ) {
        return;
    }
    if(game.state != game.allState.cuopai)return;

    clientMgr.broadcastInRoom(socket.resp.kanpai_notify,{userId:userId},userId,true);
    recordGameAction(game,socket.resp.kanpai_notify,{userId:userId});
}
exports.liangpai = function (userId) {
    var roomId = roomMgr.getUserRoomId(userId);
    if(roomId == null){
        return;
    }
    var seatIndex = roomMgr.getUserIndex(userId);
    if(seatIndex == null){
        return;
    }
    var game = games[ roomId ];
    if( game == null ) {
        return;
    }
    if(game.state != game.allState.cuopai)return;

    var gs = game.gameSeats[seatIndex];
    if(gs.hasLiang)return;
    gs.hasLiang = true;

    var niu = calculate(game, gs.holds);
    clientMgr.broadcastInRoom(socket.resp.liangpai_notify,{userId:userId,holds: gs.holds,niu:niu,sit:gs.sit},userId,true);
    recordGameAction(game,socket.resp.liangpai_notify,{userId:userId,holds: gs.holds,niu:niu,sit:gs.sit});

    var hasOver = true;
    for (var i=0;i<game.gameSeats.length;i++) {
        var ddd = game.gameSeats[i];
        if(!ddd || ddd.sit == 0)continue;
        if(ddd.hasLiang == false){
            hasOver = false;
        }
    }
    if(hasOver){
        bipai(game,userId);
    }
}
function shuffle( game ) {
    let allCards = game.allCards;
    //初始化牌组
    for( let i = 1; i <= 13; i ++ ){
        for( let j = 1; j <= 4; j ++ ) {
            allCards.push("" + i + j);
        }
    }
    //数组重新排序
	for( let i = 0; i < allCards.length; ++i ) {
		let lastIndex = allCards.length - 1 - i;
		let index = Math.floor( Math.random() * lastIndex );
		let t = allCards[ index ];
        allCards[ index ] = allCards[ lastIndex ];
        allCards[ lastIndex ] = t;
	}
}
function deal(game){
    //强制清0
    game.currentIndex = 0;

    var seatIndex = 0;
    for(var i = 0; i < 2 * game.gameSeats.length; ++i){
        if(game.gameSeats[seatIndex] == null){
            seatIndex ++;
            seatIndex %= game.gameSeats.length;
            continue;
        }
        var holds = game.gameSeats[seatIndex].holds;
        if(holds == null){
            holds = [];
            game.gameSeats[seatIndex].holds = holds;
        }
        mopai(game,seatIndex);
        seatIndex ++;
        seatIndex %= game.gameSeats.length;
    }
}
function mopai( game, seatIndex ) {
    if(game.currentIndex == game.allCards.length){
        return -1;
    }
    var data = game.gameSeats[seatIndex];
    var holds = data.holds;
    var pai = game.allCards[game.currentIndex];
    game.currentIndex ++;
    holds.push( pai );
    return pai;
}
// function createNiuniu( game ) {
//     var setNiuniu = false;
//     var index = -1;
//     for(var i = 0; i < game.gameSeats.length; ++i){
//         if(game.gameSeats[i] == null){
//             continue;
//         }
//         var seats = game.gameSeats[i];
//         if(seats.setNiuniu){
//             game.roomInfo.seats[i].setNiuniu = false;
//             setNiuniu = true;
//             index = i;
//         }
//     }

//     if(setNiuniu == false) return;
//     var maxIndex = -1;
//     var maxNiu = -1;
//     var maxNiuArr = [];
//     for(var i = 0; i < game.gameSeats.length; ++i) {
//         if (game.gameSeats[i] == null) {
//             continue;
//         }
//         var holds = game.gameSeats[i].holds;
//         var value = calculate(holds);
//         if(value > maxNiu){
//             maxNiu = value;
//             maxNiuArr = [i];
//         }
//         else if(value == maxNiu){
//             maxNiuArr.push(i);
//         }
//     }
//     if(maxNiuArr.length == 1){
//         maxIndex = maxNiuArr[0];
//     }
//     else{
//         var temp = maxNiuArr[0];
//         var seatData = game.gameSeats[temp];
//         for(var j = 1; j < maxNiuArr.length; ++j){
//             seatData = game.gameSeats[temp];
//             var sd = game.gameSeats[maxNiuArr[j]];
//             var result = compare(seatData.holds,sd.holds,maxNiu);
//             if(result < 0){
//                 temp = maxNiuArr[j];
//             }
//         }
//         maxIndex = temp;
//     }

//     var holds_temp = game.gameSeats[index].holds;
//     game.gameSeats[index].holds = game.gameSeats[maxIndex].holds;
//     game.gameSeats[maxIndex].holds = holds_temp;
// }

// function createNiuniu2( game ) {
//     var setNiuniu = false;
//     var index1 = -1;
//     var index2 = -1;
//     for(var i = 0; i < game.gameSeats.length; ++i){
//         if(game.gameSeats[i] == null){
//             continue;
//         }
//         var seats = game.gameSeats[i];
//         var rate = seats.setNiuniu2;
//         if(rate == 0)continue;
//         var rate2 = Math.abs(rate);
//         var randNum = Math.random() * 100;
//         logger.game_log("Control:",rate2,randNum);
//         if(randNum < rate2){
//             if(rate > 0) {
//                 index1 = i;
//             }
//             else{
//                 index2 = i;
//             }
//             setNiuniu = true;
//         }
//     }
//     if(setNiuniu == false) return;
//     var maxIndex = -1;
//     var maxNiu = -1;
//     var minIndex = 0;
//     var minNiu = 10;
//     var maxNiuArr = [];
//     for(var i = 0; i < game.gameSeats.length; ++i) {
//         if (game.gameSeats[i] == null) {
//             continue;
//         }
//         var holds = game.gameSeats[i].holds;
//         var value = calculate(holds);
//         if(value > maxNiu){
//             maxNiu = value;
//             maxNiuArr = [i];
//         }
//         else if(value == maxNiu){
//             maxNiuArr.push(i);
//         }
//         if(value < minNiu){
//             minNiu = value;
//             minIndex = i;
//         }
//     }
//     if(maxNiuArr.length == 1){
//         maxIndex = maxNiuArr[0];
//     }
//     else{
//         var temp = maxNiuArr[0];
//         var seatData = game.gameSeats[temp];
//         for(var j = 1; j < maxNiuArr.length; ++j){
//             seatData = game.gameSeats[temp];
//             var sd = game.gameSeats[maxNiuArr[j]];
//             var result = compare(seatData.holds,sd.holds,maxNiu);
//             if(result < 0){
//                 temp = maxNiuArr[j];
//             }
//         }
//         maxIndex = temp;
//     }

//     if(index1 > 0){
//         var holds_temp = game.gameSeats[index1].holds;
//         game.gameSeats[index1].holds = game.gameSeats[maxIndex].holds;
//         game.gameSeats[maxIndex].holds = holds_temp;
//     }
//     if(index2 > 0 && index2 != minIndex){
//         var holds_temp2 = game.gameSeats[index2].holds;
//         game.gameSeats[index2].holds = game.gameSeats[minIndex].holds;
//         game.gameSeats[minIndex].holds = holds_temp2;
//     }
// }


// 获取花色
function getCardDecor(card) {
    return card % 10;
}

// 获取牌的值
function getCardValue(card) {
    return Math.floor(card / 10);
}

// 获取牌的点数
function getCardPoint(card) {
    var value = getCardValue(card);
    return value == 1 ? 14 : value;
}

//顺子
function isStraight(cards) {
    var dict = {};
    var minValue = 99;
    var maxValue = 0;
    for (var i = 0; i < cards.length; i++) {
        var value = getCardValue(cards[i]);
        if (value < minValue) {
            minValue = value;
        }
        if (value > maxValue) {
            maxValue = value;
        }
        if (dict[value]) {  // 有对子或者豹子，肯定不是顺子
            return false;
        }
        dict[value] = 1;
    }
    
    if ((maxValue - minValue + 1) == cards.length) {    // A23 ~ JQK
        return true;
    }

    if (dict[12] && dict[13] && dict[1]) {  // QKA
        return true;
    }
    return false;
}
//同花
function isSameDecor(cards) {
    var decor;
    for (var i = 0; i < cards.length; i++) {
        var type = getCardDecor(cards[i]);
        if(decor == null){
            decor = type;
        }
        else if(type != decor){
            return false;
        }
    }
    return true;
}

// 同花顺
function isSameDecorStraight(cards) {
    if (!isSameDecor(cards)) {
        return false;
    }
    if (!isStraight(cards)) {
        return false;
    }
    return true;
}

// 豹子
function isLeopard(cards) {
    var firstValue;
    for (var i = 0; i < cards.length; i++) {
        var value = getCardValue(cards[i]);
        if(firstValue == null){
            firstValue = value;
        }
        else if(value != firstValue){
            return false;
        }
    }
    return true;
}

// //葫芦牛
// function checkHulu( cards ) {
//     var dict = {};
//     for (var i = 0; i < cards.length; i++) {
//         var card = parseInt(cards[i]);
//         var value = Math.floor(card / 10);
//         dict[value] = dict[value] === undefined ? 1 : dict[value] + 1;
//     }
//     var count = [];
//     for (var i in dict) {
//         count.push(dict[i]);
//     }
//     if(count.length == 2 && (count[0] == 3 || count[1] == 3)){
//         logger.game_log("葫芦牛22222222222222222222",count,cards);
//         return true;
//     }
//     return false;
// }
// //炸弹牛
// function checkZhadan( cards ) {
//     var dict = {};
//     for (var i = 0; i < cards.length; i++) {
//         var card = parseInt(cards[i]);
//         var value = Math.floor(card / 10);
//         dict[value] = dict[value] === undefined ? 1 : dict[value] + 1;
//     }
//     var count = [];
//     for (var i in dict) {
//         count.push(dict[i]);
//     }
//     if(count.length == 2 && (count[0] == 4 || count[1] == 4)){
//         logger.game_log("炸弹牛2222222222222222222",count,cards);
//         return true;
//     }
//     return false;
// }
// //五小牛
// function checkWuxiao( cards ) {
//     var total = 0;
//     for (var i = 0; i < cards.length; i++) {
//         var card = parseInt(cards[i]);
//         var value = Math.floor(card / 10);
//         total += value;
//     }
//     if(total <= 10)return true;
//     return false;
// }
// //五花牛
// function checkWuhua( cards ) {
//     var isWuhuaniu = true;
//     for (var i = 0; i < cards.length; i++) {
//         var card = parseInt(cards[i]);
//         if(card <= 104){
//             isWuhuaniu = false;
//         }
//     }
//     return isWuhuaniu;
// }

function getMixCardPoint(cards) {
    var dict = {};
    for (var i = 0; i < cards.length; ++i) {
        var value = getCardValue(cards[i]);
        dict[value] = dict[value] ? dict[value] + 1 : 1;
    }

    var point = 0;
    for (var i = 2; i <= 14; ++i) {
        var value = i > 13 ? i - 13 : i;
        while (dict[value] && dict[value] > 0) {
            --dict[value];
            point = point * 20 + i;
        }
    }
    return point;
}

function getPairCardPoint(cards) {
    var dict = {};
    for (var i = 0; i < cards.length; ++i) {
        var value = getCardPoint(cards[i]);
        dict[value] = dict[value] ? dict[value] + 1 : 1;
    }

    var amount = [];
    for (var value in dict) {
        if (!amount[dict[value]]) {
            amount[dict[value]] = [];
        }
        amount[dict[value]].push(value);
    }

    var point = 0;
    for (var i = 4; i >= 1; --i) {
        if (!amount[i]) continue;
        for (var j = 14; j > 1; --j) {
            if (findArrData(amount[i], j) < 0) continue;
            for (var k = 0; k < i; ++k) {
                point = point * 20 + j;
            }
        }
    }
    return point;
}

function getCardType(game, cards) {
    var holds = [];
    holds = holds.concat(cards);
    holds = holds.concat(game.commonHolds);

    var tryCards = trySameDecorStraight(holds);
    if (tryCards) {
        for (let i = 0; i < cards.length; i++) {
            let value = getCardPoint(holds);
            if (value == 14) {
                return CARD_TYPE.ROYAL_SAME_DECOR_STRAIGHT;
            }
        }
        return CARD_TYPE.SAME_DECOR_STRAIGHT;
    }
    tryCards = tryBomb(holds);
    if (tryCards) {
        return CARD_TYPE.BOMB;
    }
    tryCards = tryGourd(holds);
    if (tryCards) {
        return CARD_TYPE.GOURD;
    }
    tryCards = trySameDecor(holds);
    if (tryCards) {
        return CARD_TYPE.SAME_DECOR;
    }
    tryCards = tryStraight(holds);
    if (tryCards) {
        return CARD_TYPE.STRAIGHT;
    }
    tryCards = tryLeopard(holds);
    if (tryCards) {
        return CARD_TYPE.LEOPARD;
    }
    tryCards = tryTwoPair(holds);
    if (tryCards) {
        return CARD_TYPE.TWO_PAIR;
    }
    tryCards = tryOnePair(holds);
    if (tryCards) {
        return CARD_TYPE.ONE_PAIR;
    }
    return 0;
}

//计算最终为牛几
function calculate(game, cards) {
    var holds = [];
    holds = holds.concat(cards);
    holds = holds.concat(game.commonHolds);

    var tryCards = trySameDecorStraight(holds);
    if (tryCards) {
        return 90000000 + getPairCardPoint(tryCards);
    }
    tryCards = tryBomb(holds);
    if (tryCards) {
        return 80000000 + getPairCardPoint(tryCards);
    }
    tryCards = tryGourd(holds);
    if (tryCards) {
        return 70000000 + getPairCardPoint(tryCards);
    }
    tryCards = trySameDecor(holds);
    if (tryCards) {
        return 60000000 + getPairCardPoint(tryCards);
    }
    tryCards = tryStraight(holds);
    if (tryCards) {
        return 50000000 + getPairCardPoint(tryCards);
    }
    tryCards = tryLeopard(holds);
    if (tryCards) {
        return 40000000 + getPairCardPoint(tryCards);
    }
    tryCards = tryTwoPair(holds);
    if (tryCards) {
        return 30000000 + getPairCardPoint(tryCards);
    }
    tryCards = tryOnePair(holds);
    if (tryCards) {
        return 20000000 + getPairCardPoint(tryCards);
    }
    tryCards = tryMixCard(holds);
    if (tryCards) {
        return 10000000 + getPairCardPoint(tryCards);
    }
    return getMixCardPoint(holds);
}

function getTryCards(game, cards) {
    var holds = [];
    holds = holds.concat(cards);
    holds = holds.concat(game.commonHolds);

    var tryCards = trySameDecorStraight(holds);
    if (tryCards) {
        return tryCards;
    }
    tryCards = tryBomb(holds);
    if (tryCards) {
        return tryCards;
    }
    tryCards = tryGourd(holds);
    if (tryCards) {
        return tryCards;
    }
    tryCards = trySameDecor(holds);
    if (tryCards) {
        return tryCards;
    }
    tryCards = tryStraight(holds);
    if (tryCards) {
        return tryCards;
    }
    tryCards = tryLeopard(holds);
    if (tryCards) {
        return tryCards;
    }
    tryCards = tryTwoPair(holds);
    if (tryCards) {
        return tryCards;
    }
    tryCards = tryOnePair(holds);
    if (tryCards) {
        return tryCards;
    }
    return tryMixCard(holds);
}

function trySameDecorStraight(cards) {
    var dict = {};
    for (var i = 0; i < cards.length; ++i) {
        dict[cards[i]] = dict[cards[i]] ? (dict[cards[i]] + 1) : 1;
    }
    var res = [];
    for (var decor = 1; decor < 4; ++decor) {
        var cnt = 0;
        for (var point = 14; point >= 2; --point) {
            var value = (point > 13) ? (point - 13) : point;
            var card = value * 10 + decor;
            if (dict[card]) {
                cnt++;
                res.push(card);
                if (cnt == 5) {
                    return res;
                }
            } else {
                cnt = 0;
                res = [];
            }
        }
    }
}

function tryBomb(cards) {
    var dict = {};
    for (var i = 0; i < cards.length; ++i) {
        var value = getCardValue(cards[i]);
        dict[value] = dict[value] ? (dict[value] + 1) : 1;
    }
    var bomb;
    for (var value in dict) {
        if (dict[value] == 4) {
            bomb = value;
            break;
        }
    }
    if (bomb) {     // 有炸弹
        for (var i = 14; i > 1; --i) {
            var value = (i > 13) ? (i - 13) : i;
            if (value == bomb) {
                continue;
            }
            if (dict[value]) {  // 再找一张杂牌
                var res = [];
                var hasMix = false;
                for (var i = 0; i < cards.length; ++i) {
                    var value2 = getCardValue(cards[i]);
                    if (value2 == bomb) {
                        res.push(cards[i]);
                    } else if (value2 == value) {
                        if (!hasMix) {
                            res.push(cards[i]);
                        }
                        hasMix = true;
                    }
                }
                return res;
            }
        }
    }
}

function tryGourd(cards) {
    var dict = {};
    for (var i = 0; i < cards.length; ++i) {
        var value = getCardValue(cards[i]);
        dict[value] = dict[value] ? (dict[value] + 1) : 1;
    }
    var three, two;
    var cnt = [];
    for (var value in dict) {
        cnt[dict[value]] = cnt[dict[value]] ? (cnt[dict[value]] + 1) : 1;
    }
    if (cnt[3] && cnt[2]) {
        for (var i = 14; i > 1; --i) {
            var value = (i > 13) ? (i - 13) : i;
            if (dict[value] == 2) {
                if (!two) {
                    two = value;
                }
            }
            if (dict[value] == 3) {
                if (!three) {
                    three = value;
                }
            }
        }
        var res = [];
        for (var i = 0; i < cards.length; ++i) {
            var value = getCardValue(cards[i]);
            if (value == two || value == three) {
                res.push(cards[i]);
            }
        }
        return res;
    }
}

function trySameDecor(cards) {
    var dict = {};
    for (var i = 0; i < cards.length; ++i) {
        var decor = getCardDecor(cards[i]);
        dict[decor] = dict[decor] ? (dict[decor] + 1) : 1;
    }
    for (var decor = 1; decor <= 4; ++decor) {
        if (dict[decor] && dict[decor] >= 5) {
            var res2 = [];
            for (var i = 0; i < cards.length; ++i) {
                if (getCardDecor(cards[i]) == decor) {
                    res2.push(cards[i]);
                }
            }
            var res = [];
            for (var point = 14; point > 1; --point) {
                var value = (point > 13) ? (point - 13) : point;
                var card = value * 10 + decor;
                if (findArrData(res2, card) >= 0) {
                    res.push(card);
                    if (res.length == 5) {
                        return res;
                    }
                }
            }
        }
    }
}

function tryStraight(cards) {
    var dict = {};
    for (var i = 0; i < cards.length; ++i) {
        var value = getCardValue(cards[i]);
        dict[value] = dict[value] ? (dict[value] + 1) : 1;
    }
    var cnt = 0;
    for (var point = 14; point > 1; --point) {
        var value = (point > 13) ? (point - 13) : point;
        if (dict[value]) {
            cnt++;
            if (cnt == 5) {
                var res = [];
                for (var item = point; item < point + 5; ++item){
                    for (var i = 0; i < cards.length; ++i) {
                        if (getCardValue(cards[i]) == item) {
                            res.push(cards[i]);
                            break;
                        }
                    }
                }
                return res;
            }
        } else {
            cnt = 0;
        }
    }
}

function tryLeopard(cards) {
    var dict = {};
    for (var i = 0; i < cards.length; ++i) {
        var value = getCardValue(cards[i]);
        dict[value] = dict[value] ? (dict[value] + 1) : 1;
    }
    for (var value in dict) {
        if (dict[value] == 3) {
            var mix = [];
            for (var point = 14; point > 1; --point) {
                var v = (point > 13) ? (point - 13) : point;
                if (v == value) continue;
                if (dict[v] == 1) {
                    mix.push(v);
                    if (mix.length >= 2) {
                        break;
                    }
                }
            }
            var res = [];
            for (var i = 0; i < cards.length; ++i) {
                var v = getCardValue(cards[i]);
                if (v == value) {
                    res.push(cards[i]);
                } else if (findArrData(mix, v) >= 0) {
                    res.push(cards[i]);
                }
            }
            return res;
        }
    }
}

function tryTwoPair(cards) {
    var dict = {};
    for (var i = 0; i < cards.length; ++i) {
        var value = getCardValue(cards[i]);
        dict[value] = dict[value] ? (dict[value] + 1) : 1;
    }
    var cnt = [];
    for (var value in dict) {
        cnt[dict[value]] = cnt[dict[value]] ? (cnt[dict[value]] + 1) : 1;
    }
    if (cnt[2] >= 2) {
        var mix;
        var pair = [];
        for (var point = 14; point > 1; --point) {
            var value = (point > 13) ? (point - 13) : point;
            if (!dict[value]) continue;
            if (dict[value] == 2) {
                if (pair.length < 2) {
                    pair.push(value);
                }
            } else if (dict[value] == 1) {
                if (mix == null) {
                    mix = value;
                }
            }
        }
        
        var res = [];
        for (var i = 0; i < cards.length; ++i) {
            var value = getCardValue(cards[i]);
            if (value == mix) {
                res.push(cards[i]);
                mix = null;
            } else if (findArrData(pair, value) >= 0) {
                res.push(cards[i]);
            }
        }
        return res;
    }
}

function findArrData(arr, value) {
    var index = arr.indexOf("" + value);
    if (index < 0) {
        index = arr.indexOf(value);
    }
    return index;
}

function tryOnePair(cards) {
    var dict = {};
    for (var i = 0; i < cards.length; ++i) {
        var value = getCardValue(cards[i]);
        dict[value] = dict[value] ? (dict[value] + 1) : 1;
    }
    var cnt = [];
    for (var value in dict) {
        cnt[dict[value]] = cnt[dict[value]] ? (cnt[dict[value]] + 1) : 1;
    }
    if (cnt[2] >= 1) {
        var mix = [];
        var pair;
        for (var point = 14; point > 1; --point) {
            var value = (point > 13) ? (point - 13) : point;
            if (!dict[value]) continue;
            if (dict[value] == 2) {
                if (pair == null) {
                    pair = value;
                }
            } else if (dict[value] == 1) {
                if (mix.length < 3) {
                    mix.push(value);
                }
            }
        }
        
        var res = [];
        for (var i = 0; i < cards.length; ++i) {
            var value = getCardValue(cards[i]);
            if (value == pair) {
                res.push(cards[i]);
            } else if (findArrData(mix, value) >= 0) {
                res.push(cards[i]);
            }
        }
        return res;
    }
}

function tryMixCard(cards) {
    var dict = {};
    var map = {};
    for (var i = 0; i < cards.length; ++i) {
        var value = getCardValue(cards[i]);
        dict[value] = dict[value] ? (dict[value] + 1) : 1;
        map[value] = cards[i];
    }
    var res = [];
    for (var point = 14; point > 1; --point) {
        var value = (point > 13) ? (point - 13) : point;
        if (dict[value]) {
            res.push(map[value]);
            if (res.length == 5) {
                return res;
            }
        }
    }
}

function compareDecor(cardA, cardB) {
    let decorA = getCardDecor(cardA);
    let decorB = getCardDecor(cardB);
    return decorA - decorB;
}

function compareCards(cardsA, cardsB) {
    let sortFunc = (a, b) => { return getCardPoint(b) - getCardPoint(a); };
    cardsA.sort(sortFunc);
    cardsB.sort(sortFunc);
    for (let i = 0; i < cardsA.length; i++) {
        let cardA = cardsA[i];
        let cardB = cardsB[i];
        if (getCardPoint(cardA) != getCardPoint(cardB)) {
            return getCardPoint(cardB) - getCardPoint(cardA);
        }
    }
    for (let i = 0; i < cardsA.length; i++) {
        let cardA = cardsA[i];
        let cardB = cardsB[i];
        let cmp = compareDecor(cardA, cardB);
        if (cmp != 0) {
            return cmp;
        }
    }
    return 0;
}

function better(gamberA, gamberB) {
    if (gamberA.tryCards && gamberB.tryCards) {
        let cmp = compareCards(gamberA.tryCards, gamberB.tryCards);
        if (cmp != 0) {
            return cmp > 0;
        }
    }
    return compareCards(gamberA.holds, gamberB.holds);
}

function calculateResult(game,roomInfo){
    var winner = [];
    var winValue = 0;

    for (var i = 0; i < game.gameSeats.length; ++i) {
        var index = (i + game.button) % game.gameSeats.length;  // 从庄家开始轮
        var gamber = game.gameSeats[index];
        if (gamber == null || gamber.sit == 0) continue;
        if (gamber.eliminate) continue;     // 玩家被淘汰了
        var value = calculate(game, gamber.holds);
        gamber.niu = getCardType(game, gamber.holds);
        gamber.tryCards = getTryCards(game, gamber.holds);
        if (gamber.tryCards) {
            gamber.tryCards.sort((a, b) => { return getCardPoint(a) - getCardPoint(b); });
        }
        logger.game_log("玩家", gamber.userId, "的手牌是", gamber.holds, "公共牌是", game.commonHolds, "尝试组牌为", gamber.tryCards, "得分是", value);
        if (winner == null || value > winValue) {
            winner = [gamber];
            winValue = value;
        } else if (value == winValue) {
            if (better(winner[0], gamber)) {
                winner = [gamber];
            }
            // winner.push(gamber);
        }
    }

    // if (winner == null) {
    //     for (var i = 1; i < game.gameSeats.length; ++i) {
    //         var index = (game.gameSeats.length - i + game.button) % game.gameSeats.length;  // 从庄家开始轮
    //         var gamber = game.gameSeats[index];
    //         // logger.game_log("全弃:", gamber);
    //         if (gamber == null || gamber.sit == 0) continue;
    //         winner = gamber;
    //         break;
    //     }
    // }
    // 定庄
    roomInfo.smallBlindBetIndex = game.smallBlindBetIndex;
    
    var winnerScore = 0;
    for (var i = 0; i < game.gameSeats.length; ++i) {
        var gamber = game.gameSeats[i];
        if (gamber == null || gamber.sit == 0) continue;
        
        // if (winner.indexOf(gamber) < 0) {
            // gamber.score = -gamber.scoreBetting;
            winnerScore += gamber.scoreBetting;
        // }
    }
    var score = Math.floor(winnerScore / winner.length);
    var remain = winnerScore % winner.length;
    for (var i = 0; i < winner.length; ++i) {
        var gamber = winner[i];
        if (i == 0) {
            changeScore(game, gamber, -(score + remain), true);
            // gamber.score += score + remain;
        } else {
            changeScore(game, gamber, -score, true);
        }
    }
}

function doGameOver(game,userId,forceEnd){
    var roomId = roomMgr.getUserRoomId(userId);
    doGameOver2(game,roomId,forceEnd);
}
function doGameOver2(game,roomId,forceEnd){
	if(roomId == null){
		return;
	}
	var roomInfo = roomMgr.getRoom(roomId);
	if(roomInfo == null){
		return;
	}
	roomInfo.gameState = "idle";
    clientMgr.broadcastInRoom2(socket.resp.game_state,{state:roomInfo.gameState},roomId);

	var results = [];
    var dbusers = [];
	var dbresult = [];
    var backcount = 0,renshu = 0;
    var isEnd = false;
    var endInfo = null;

	if(game != null){
	    if(!forceEnd){
			calculateResult(game,roomInfo);	
		}

        if(roomInfo.allRecord == null){
	        roomInfo.allRecord = [];
            roomInfo.allRecord[0] = {};
        }
        var record;
        if(roomInfo.conf.maxGames > 0){
            record = roomInfo.allRecord[roomInfo.numOfGames] = {};
        }
        else{
            record = roomInfo.allRecord = {};
        }
        var endTime = Date.now();
        var cost_coins = function (data,rs) {
            db.rate_coins(data,function (info) {
                var difen = game.conf.difen;
                // if(info.coins <= difen){
                //     rs.sit = 0;
                //     exports.sitDown(rs.userId,false);
                // }
                data.coins = info.coins;
                data.score = -1 * info.cost;
                record[data.userId].score = -1 * info.cost;
                backcount ++;

                //如果局数已够，则进行整体结算，并关闭房间
                if(backcount >= renshu){
                    clientMgr.broadcastInRoom2(socket.resp.game_over,{results:results,endInfo:endInfo,endTime:endTime,record:record},roomId);
                    if(isEnd){
                        // clientMgr.broadcastInRoom2(socket.resp.dispress,"dispress",roomId);
                        clientMgr.kickAllInRoom(roomId);
                        roomMgr.destroy(roomId);
                    }
                }
            });
        }
		for(var i = 0; i < roomInfo.seats.length; ++i){
			var rs = roomInfo.seats[i];
			var sd = game.gameSeats[i];
            if(rs.shangzhuang == null){
                rs.shangzhuang = 0;
            }
            if(rs.niuniu == null){
                rs.niuniu = 0;
            }
            if(rs.win == null){
                rs.win = 0;
            }
			if( sd == null || sd.sit == 0 || sd.userId <= 0) continue;
            renshu ++;
            rs.shangzhuang += game.button == i?1:0;
            rs.niuniu += sd.isNiuniu?1:0;
            rs.win += sd.score > 0?1:0;

			// rs.coins += sd.score;
            // rs.score += sd.score;
            rs.ready = false;

            record[sd.userId] = {score:sd.score,holds:sd.holds,tryCards:sd.tryCards,niu:sd.niu,isZhuang:game.button == i};

			var userRT = {
				userId:sd.userId,
                area : rs.area,
                coins:rs.coins,
                score:sd.score,
			};
			// results.push(userRT);
            dbusers.push(sd.userId);
			dbresult.push(sd.score);
			sd.game = null;	//清除数据
			delete gameSeatsOfUsers[sd.userId];

            // logger.game_log("计算金币", userRT, rs);
            cost_coins(userRT,rs);
		}
		delete games[roomId];
	}
    var fnNoticeResult = function(isEnd){
        roomInfo.settle = roomInfo.settle || {};
        for(var i = 0; i < roomInfo.seats.length; ++i){
            var rs = roomInfo.seats[i];
            if(rs.userId <= 0)continue;
            if(rs.shangzhuang == null){
                rs.shangzhuang = 0;
            }
            if(rs.niuniu == null){
                rs.niuniu = 0;
            }
            if(rs.win == null){
                rs.win = 0;
            }
            roomInfo.settle[rs.userId] = {
                userId:rs.userId,
                score:rs.score,
                shangzhuang:rs.shangzhuang,
                niuniu:rs.niuniu,
                win:rs.win,
            };
        }
        if(isEnd){
            endInfo = [];
            for (let userId in roomInfo.settle) {
                endInfo.push(roomInfo.settle[userId]);
            }
        }

        if( isEnd ){
            if( roomInfo.numOfGames > 1) {
                store_history(game,roomInfo);
            }
        }
        else{
            setTimeout(function() {
                clearExit(roomInfo);
            }, 2000);
            
            clientMgr.broadcastInRoom2(socket.resp.next_all,{time:game.nextGameTime},roomId,true);
            recordGameAction(game,socket.resp.next_all,{time:game.nextGameTime});
            game.state = game.allState.idle;
            game.timeId5 = setTimeout(function () {
                var game = games[ roomId ];
                if( game == null ) {
                    begin(roomId);
                }
            },game.nextGameTime * 1000);
        }
    }
	if(forceEnd || game == null){
        isEnd = true;
		fnNoticeResult(true);
        clientMgr.broadcastInRoom2(socket.resp.dispress,"dispress",roomId);
        clientMgr.kickAllInRoom(roomId);
        roomMgr.destroy(roomId); 
	}
	else{
        isEnd = (roomInfo.numOfGames >= roomInfo.conf.maxGames) && roomInfo.conf.maxGames > 0;
        fnNoticeResult(isEnd);

        //记录打牌信息
        db.insert_game_records(roomId,roomInfo.type,roomInfo.createTime,roomInfo.numOfGames,dbusers,dbresult,game.actionList);
	}
}

function recordGameAction(game,cmd,result){
	game.actionList.push({cmd:cmd,result:result});
}

function store_history(game,roomInfo){
	var seats = roomInfo.seats;
	var history = {
		roomId:roomInfo.roomId,
        type : roomInfo.type,
        owner : roomInfo.owner,
        index : roomInfo.numOfGames,
		time:roomInfo.createTime,
        conf:roomInfo.conf,
        url : roomInfo.url,
		seats:[]
	};

	for(var i = 0; i < seats.length; ++i){
		var rs = seats[i];
		if(rs.userId <= 0){
		    continue;
        }
        var hs = history.seats[i] = {};
		hs.userId = rs.userId;
		hs.name = crypto.fromBase64(rs.userName);
		hs.score = rs.score;
	}
	db.store_history(history);
}

exports.hasBegan = function(roomId){
	var game = games[roomId];
	if(game && game.state != 0){
		return true;
	}
	// var roomInfo = roomMgr.getRoom(roomId);
	// if(roomInfo != null){
    //     return roomInfo.gameState == "playing";
	// 	// return roomInfo.numOfGames > 0;
	// }
	return false;
};
function changeScore(game, gamber, value, over=false) {
    if( gamber == null || gamber.sit == 0 || gamber.userId <= 0) return;
    let userId = gamber.userId;
    var rs = roomMgr.getSeatUser(userId);

    rs.coins -= value;
    rs.score -= value;

    var userRT = {
        userId:userId,
        area : rs.area,
        coins:rs.coins,
        score:-value,
    };
    db.rate_coins(userRT);

    gamber.score -= value;
    game.fundPool += value;
    var results;// = [{userId:gamber.userId,score:-value,totalBetting: over ? 0 : -gamber.score}];
    if (over) {
        results = [{userId:gamber.userId,score:-value,totalBetting:-gamber.score - value}];
        // for (let i = 0; i < game.gameSeats.length; i++) {
        //     let sd = game.gameSeats[i];
        //     if (sd == null || sd.sit == 0) continue;
        //     if (sd == gamber) continue;
        //     results.push({userId:sd.userId, totalBetting: 0});
        // }
    } else {
        results = [{userId:gamber.userId,score:-value,totalBetting:-gamber.score}];
    }
    clientMgr.broadcastInRoom(socket.resp.dizhu_cost,{results:results,fundPool:game.fundPool},userId,true);
    recordGameAction(game,socket.resp.dizhu_cost,{results:results,fundPool:game.fundPool});
}

function updatePermission(userId) {
    db.niuniu_permission(userId, function(times) {
        if (times != 0) {
            console.warn(userId, "没有权限");
            return ;
        }
        
        clientMgr.sendMsg(userId, socket.resp.update_permission);
    });
}

exports.perspective = function(roomId, userId){
	var game = games[roomId];
	if(game == null){
		return;
	}
	var roomInfo = roomMgr.getRoom(roomId);
	if(roomInfo == null){
		return;
	}
    db.niuniu_permission(userId, function(times) {
        if (times != 0) {
            console.warn(userId, "想要透视，没有权限");
            return ;
        }
        var seats = roomInfo.seats;
        var allHolds = [];
        for(var i = 0; i < seats.length; ++i) {
            if (!game.gameSeats[i]) continue;
            allHolds.push({userId:seats[i].userId,holds:game.gameSeats[i].holds});
        }
        logger.game_log("透视的牌", allHolds);
        clientMgr.sendMsg(userId, socket.resp.perspective, allHolds);
        recordGameAction(game,socket.resp.perspective,allHolds);
    });
};

exports.replaceCardGet = function(roomId, userId){
	var game = games[roomId];
	if(game == null){
		return;
	}
	var roomInfo = roomMgr.getRoom(roomId);
	if(roomInfo == null){
		return;
	}
    db.niuniu_permission(userId, function(times) {
        if (times != 0) {
            console.warn(userId, "想要看牌堆，没有权限");
            return ;
        }
        var holds = [];
        for (var i = game.currentIndex; i < game.allCards.length; ++i) {
            holds.push(game.allCards[i]);
        }
        clientMgr.sendMsg(userId, socket.resp.replace_card_get, holds);
        recordGameAction(game,socket.resp.replace_card_get,holds);
    });
}

exports.replaceCardSet = function(roomId, userId, hold, target){
	var game = games[roomId];
	if(game == null){
		return;
	}
	var roomInfo = roomMgr.getRoom(roomId);
	if(roomInfo == null){
		return;
	}
    
    db.niuniu_permission(userId, function(times) {
        if (times != 0) {
            console.warn(userId, "想要换牌，没有权限");
            return ;
        }
        
        var findCardIndex = function(cards, card, startIndex=0) {
            for (var i = startIndex; i < cards.length; ++i) {
                if (cards[i] == card) {
                    return i;
                }
            }
            return -1;
        }
        var cardIndex = findCardIndex(game.allCards, target, game.currentIndex);
        if (cardIndex == -1) {
            logger.game_log(userId, "要替换的目标牌不存在", hold, target);
            return;
        }

        var seatIndex = roomMgr.getUserIndex(userId);
        var holds = game.gameSeats[seatIndex].holds;
        var holdIndex = findCardIndex(holds, hold);
        if (holdIndex == -1) {
            logger.game_log(userId, "要替换的手牌不存在", hold, target);
            return;
        }
        holds[holdIndex] = target;
        game.allCards[cardIndex] = hold;
        
        clientMgr.sendMsg(userId, socket.resp.replace_card_set, holds);
        recordGameAction(game,socket.resp.replace_card_set, holds);
    });
}

function update() {
    for(var userId in kickList) {
        kickList[userId] -= 1;
        var roomId = roomMgr.getUserRoomId(userId);
        if(roomId == null){
            delete kickList[userId];
            continue;
        }
        var roomInfo = roomMgr.getRoom(roomId);
        if(roomInfo == null){
            delete kickList[userId];
            continue;
        }
        if(kickList[userId] < 0){
            clientMgr.sendMsg(userId,socket.resp.exit_result,userId);
            //通知其它玩家，有人退出了房间
            clientMgr.broadcastInRoom(socket.resp.exit_notify,userId,userId,false);
            roomMgr.exitRoom(userId);
            delete kickList[userId];
        }
    }
}
setInterval( update, 1000 );